package birdsong.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.net.UnknownHostException;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import FollowME.ClientToServerMessage;
import FollowME.ServerToClientMessage;
import birdsong.dummy.ClientCommDummy;
import birdsong.dummy.ServerCommDummy;

public class ClientCommDummyTest {

	private static ClientCommDummy clientA;
	private static ClientCommDummy clientB;

	private static ServerCommDummy server;

	private ClientToServerMessage messageFromClient;
	private ServerToClientMessage messageFromServer;
	private static final String message = "METI-PL";

	private static final String A = "A";
	private static final String B = "B";
	private static final String localhost = "localhost";

	@Before
	public void setUp() throws Exception {
		server = new ServerCommDummy();
		server.start();

		clientA = new ClientCommDummy();
		clientB = new ClientCommDummy();

		clientA.connect(localhost, A);
		clientB.connect(localhost, B);
	}

	@After
	public void tearDown() throws Exception {
		clientA.disconnect();
		clientB.disconnect();

		clientA = null;
		clientB = null;

		server.stopConnections();

	}

	@Test
	public void testConnect() throws InterruptedException {
		assertNotNull(clientA);
		assertTrue(clientA.isConnected());
	}

	@Test
	public void testIsConnected() {
		reestablishesConnections();

		assertTrue(clientA.isConnected());

		clientB.disconnect();
		assertFalse(clientB.isConnected());
	}

	@Test
	public void testDisconnect() {
		reestablishesConnections();

		assertTrue(clientB.isConnected());

		clientA.disconnect();
		assertFalse(clientA.isConnected());
	}

	@Test
	public void testHasNextMessage() {
		reestablishesConnections();

		assertNotNull(message);
		server.sendBirdsongMessage(A, B, message);
		assertTrue(clientB.hasNextMessage());
		assertFalse(clientA.hasNextMessage());
	}

	@Test
	public void testGetNextMessage() {
		reestablishesConnections();
		emptyBuffer();

		assertNotNull(message);
		server.sendBirdsongMessage(A, B, message);
		assertNotNull(clientB.getNextMessage());
		messageFromServer = (ServerToClientMessage) clientB.getNextMessage();
		assertEquals(message, messageFromServer.getPayload());
	}

	@Test
	public void testSendBirdsongMessage() {
		reestablishesConnections();
		emptyBuffer();

		clientA.sendBirdsongMessage(message);
		messageFromClient = (ClientToServerMessage) server.getNextMessage();
		assertNotNull(messageFromClient);
		assertEquals(message, messageFromClient.getPayload());
	}

	@Test
	public void testFollow() {
		reestablishesConnections();
		emptyBuffer();

		clientA.follow(B);

		messageFromClient = (ClientToServerMessage) server.getNextMessage();
		assertNotNull(messageFromClient);
		assertEquals(B, messageFromClient.getPayload());
	}

	@Test
	public void testUnfollow() {
		reestablishesConnections();

		clientA.unfollow(B);

		messageFromClient = (ClientToServerMessage) server.getNextMessage();
		assertNotNull(messageFromClient);
		assertEquals(B, messageFromClient.getPayload());
	}

	private void reestablishesConnections() {
		if (!clientA.isConnected())
			try {
				clientA.connect(localhost, A);
			} catch (UnknownHostException e) {
				System.err.println("Can not make connection");
			} catch (IOException e) {
				System.err.println("Error on message");
			}

		if (!clientB.isConnected())
			try {
				clientB.connect(localhost, B);
			} catch (UnknownHostException e) {
				System.err.println("Can not make connection");
			} catch (IOException e) {
				System.err.println("Error on message");
			}
	}

	private void emptyBuffer() {
		while (server.hasNextMessage()) {
			server.getNextMessage();
		}

	}

}